package battleship.cxbr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import battleship.emss.*;

//@TODO:
// Add self to fleet if not exist
// Implement facing with dot product
// Get between enemy and fleet
// -> Determine most hostile ship (closest?)
// Go as slow as possible?

public class Evaluate {
	// Public
	public static final boolean SEND_LEFT_MESSAGE = false;
	public static boolean WAR = false;
	public static HashMap<String,Boolean> enemyLeft = new HashMap<String,Boolean>();
	
	// Private
	//private static final boolean SAFE = false;
	//private static final boolean THREAT = true;

	private static final int MY_TEAM = 0;
	private static final int BLUE_FLEET_DISTANCE = 15000;
	private static final int YELLOW_FLEET_DISTANCE = 7500;
	
	private static final int RED = 1; // Territorial
	private static final int YELLOW = 2; // Contested
	private static final int BLUE = 0; // Uncontested

	// Keep Track of Sightings
	private static HashMap<String,Status> fleet = new HashMap<String,Status>(); // My fleet
	private static HashMap<String,Status> enemy = new HashMap<String,Status>(); // Enemy (base not included)
	
	public static Status enemyBase; // There is only one
	public static Status fleetCarrier; // There is only one
	public static double targetX, targetY;
	
	public static double distance(Status from, Status to){
		return Math.sqrt((to.mx - from.mx) * (to.mx-from.mx)
						+(to.my - from.my) * (to.my-from.my));
	}
	
	public static double distance(double x1, double y1, double x2, double y2){
		return Math.sqrt((x1 - x2) * (x1 - x2)
						+(y1 - y2) * (y1 - y2));
	}
	
	// First, track subs
	public static boolean updateSightings(ArrayList<Status> detectedStatus){
		for(int i = 0; i < detectedStatus.size(); i++){ // We detect something
			Status tmpStatus = detectedStatus.get(i);
			if (tmpStatus.team != Agent.BLUE){ // Enemy
				if (tmpStatus.type == Agent.SUB){
					if (enemy.containsKey(tmpStatus.name)){
						Status s = enemy.get(tmpStatus.name);
					}
					enemy.put(tmpStatus.name, tmpStatus);
					if (!enemyLeft.containsKey(tmpStatus.name)){
						if (enemyBase != null && distance(tmpStatus, enemyBase) > 30000){
							enemyLeft.put(tmpStatus.name, Boolean.FALSE);
						}
					}
					if (!WAR && nearFleet(tmpStatus)){
						WAR = true;
						return WAR; 
					}
				} else if (tmpStatus.type == Agent.BASE){
					enemyBase = tmpStatus;
				} else if (!WAR && tmpStatus.type == Agent.TORPEDO){
					System.out.println("Enemy fired torpedo");
					WAR = true;
					return WAR;
				}
			} else {
				// Keep track of updates on our fleet
				if (fleet.containsKey(tmpStatus.name)){
					Status s = fleet.get(tmpStatus.name);
				}
				if (tmpStatus.type != Agent.SUB)
					fleet.put(tmpStatus.name, tmpStatus);
				if (tmpStatus.type == Agent.CARRIER){
					fleetCarrier = tmpStatus;
				}
			}
		}
		
		return WAR;
	}
	
	public static boolean nearFleet(Status enemy){
		Collection<Status> theFleet = fleet.values();
		Iterator<Status> fleetIter = theFleet.iterator();
		
		while (fleetIter.hasNext()){
			Status currentShip = fleetIter.next();
			double dist = distance(currentShip, enemy);
			
			if (currentShip.territory == BLUE &&
				dist < BLUE_FLEET_DISTANCE){
				WAR = true;
				System.out.println(enemy.name + " came within " + dist + " of the fleet in BLUE");
				return WAR;
				
			} else if (currentShip.territory == YELLOW &&
						dist < YELLOW_FLEET_DISTANCE){
				System.out.println(enemy.name + " came within " + dist + " of the fleet in YELLOW");
				WAR = true;
				return WAR;
			}
		}
		
		return WAR;
	}
	
	public static String highestThreat(Status self){
		double minDistance = Double.MAX_VALUE;
		Status targetShip = null;
		Status highestThreat = null;
		
		Collection<Status> theFleet = fleet.values();
		//System.out.println(theFleet);
		
		
		HashMap<String, Status>allEnemies = new HashMap<String, Status>();
		allEnemies.putAll(enemy);
		allEnemies.put(enemyBase.name, enemyBase);
		Collection<Status> theEnemy = allEnemies.values();
		
		Iterator<Status> fleetIter = theFleet.iterator();
		while (fleetIter.hasNext()){
			Status currentShip = fleetIter.next();
			Iterator<Status> enemyIter = theEnemy.iterator();
			while (enemyIter.hasNext()){
				Status currentEnemy = enemyIter.next();
				double dist = distance(currentShip, currentEnemy);
				if (dist < minDistance && currentShip.alive == 1 && currentEnemy.alive == 1){
					targetShip = currentShip;
					highestThreat = currentEnemy;
					minDistance = dist;
				}
			}
		}
		if (targetShip != null &&
			highestThreat != null){
			if (!WAR){
				//if (WorldMap.GetOwnerMeters(highestThreat.mx, highestThreat.my) == WorldMap.TERRITORIAL){
//					targetX = (targetShip.mx * 1 + highestThreat.mx) / 2;
//					targetY = (targetShip.my * 2 + highestThreat.my) / 3;
//				}
//				else 
				if (WorldMap.GetOwnerMeters(highestThreat.mx, highestThreat.my) == WorldMap.CONTESTED){
					targetX = (targetShip.mx * 1 + highestThreat.mx * 2) / 3;
					targetY = (targetShip.my * 1 + highestThreat.my * 2) / 3;
				} else {
					targetX = (targetShip.mx * 1 + highestThreat.mx) / 2;
					targetY = (targetShip.my * 2 + enemyBase.my) / 3;
				}

			}
		}
		return new String(highestThreat.name + " to " + targetShip.name);
	}
	
	/*
	public static double deadReckon(double currentX, double currentY, double time){
		double deltaX = currentX - lastX;
		double deltaY = currentY - lastY;
		double deltaTime = time - lastTime;
		double futureX = (deltaX / deltaTime) * 1;
		double futureY = (deltaX / deltaTime) * 1;
		return 1.0d;
		
	}
	
	public static double speed(double x, double y){
		double deltaX = Math.pow(myLastX - x,2);
		double deltaY = Math.pow(myLastY - y,2);
		double deltaT = Math.max(physics.SimTime - lastTime, 1);
		double speed = Math.sqrt(deltaX + deltaY);
		if ((int)speed > 1){
			speed /= deltaT;
			lastSpeed = speed;
			lastTime = physics.SimTime;
			//System.out.println(speed);
			return speed;
		}
		return lastSpeed;
	}
	*/
		
}
